#!/usr/bin/env python
# encoding: utf-8
import wx, os
from audio import Grain, FxSwitch
from pyo import *

s = Server().boot()
s.amp = 0.5

class Surface1(wx.Panel):
    def __init__(self, parent, pos, size, callback):
        wx.Panel.__init__(self, parent, pos=pos, size=size)
        
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)

        self.callback = callback
       
        self.pos = (200,100)
        
        self.circlePos = (200,100)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
        self.Bind(wx.EVT_MOTION, self.OnMotion)

    def OnMouseDown(self, evt):
       
        self.CaptureMouse()
        self.pos = evt.GetPosition()
        self.Refresh()

    def OnMouseUp(self, evt):
        if self.HasCapture():
            self.ReleaseMouse()
            self.pos = None
            self.Refresh()

    def OnMotion(self, evt):
        if self.HasCapture():
            w,h = self.GetSize()
            self.pos = evt.GetPosition()
            if self.pos[0] < 0:
                self.pos[0] = 0
            elif self.pos[0] > w:
                self.pos[0] = w
            if self.pos[1] < 0:
                self.pos[1] = 0
            elif self.pos[1] > h:
                self.pos[1] = h
            self.Refresh()

    def OnPaint(self, evt):
        w,h = self.GetSize()
        dc = wx.AutoBufferedPaintDC(self)
        dc.SetBrush(wx.Brush("#444444"))
        dc.DrawRectangle(0, 0, w, h)
        dc.SetPen(wx.Pen("#666666", 1))
        for i in range(0, 400, 50):
            dc.DrawLine(0, i, w, i)
            dc.DrawLine(i, 0, i, h)
        dc.SetPen(wx.Pen("#AAAAAA", 1))
        if self.pos != None:
            self.circlePos = self.pos
            dc.DrawLine(0, self.pos[1], w, self.pos[1])
            dc.DrawLine(self.pos[0], 0, self.pos[0], h)
            x = self.pos[0] / float(w)
            y = 1. - self.pos[1] / float(h)
            dc.DrawText("%.3f, %.3f" % (x,y), 10, 10)
            self.callback(x, y)
            
        dc.SetBrush(wx.Brush("#AA0000"))
        dc.DrawCircle(self.circlePos[0], self.circlePos[1], 5)

class Surface2(wx.Panel):
    def __init__(self, parent, pos, size, callback):
        wx.Panel.__init__(self, parent, pos=pos, size=size)
        
        self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)

        self.callback = callback
       
        self.pos = (200,100)
        
        self.circlePos = (200,100)

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown)
        self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp)
        self.Bind(wx.EVT_MOTION, self.OnMotion)

    def OnMouseDown(self, evt):
       
        self.CaptureMouse()
        self.pos = evt.GetPosition()
        self.Refresh()

    def OnMouseUp(self, evt):
        if self.HasCapture():
            self.ReleaseMouse()
            self.pos = None
            self.Refresh()

    def OnMotion(self, evt):
        if self.HasCapture():
            w,h = self.GetSize()
            self.pos = evt.GetPosition()
            if self.pos[0] < 0:
                self.pos[0] = 0
            elif self.pos[0] > w:
                self.pos[0] = w
            if self.pos[1] < 0:
                self.pos[1] = 0
            elif self.pos[1] > h:
                self.pos[1] = h
            self.Refresh()

    def OnPaint(self, evt):
        w,h = self.GetSize()
        dc = wx.AutoBufferedPaintDC(self)
        dc.SetBrush(wx.Brush("#444444"))
        dc.DrawRectangle(0, 0, w, h)
        dc.SetPen(wx.Pen("#666666", 1))
        for i in range(0, 400, 50):
            dc.DrawLine(0, i, w, i)
            dc.DrawLine(i, 0, i, h)
        dc.SetPen(wx.Pen("#AAAAAA", 1))
        if self.pos != None:
            self.circlePos = self.pos
            dc.DrawLine(0, self.pos[1], w, self.pos[1])
            dc.DrawLine(self.pos[0], 0, self.pos[0], h)
            x = self.pos[0] / float(w)*2.
            y = 2. - self.pos[1] / float(h)*2.
            dc.DrawText("%.3f, %.3f" % (x,y), 10, 10)
            self.callback(x, y)
            
        dc.SetBrush(wx.Brush("#AA0000"))
        dc.DrawCircle(self.circlePos[0], self.circlePos[1], 5)

class MyFrame(wx.Frame):
    def __init__(self, parent=None, title="Grain Surface Controller", pos=(100,100),
                 size=(600,600)):
        wx.Frame.__init__(self, parent, id=-1, title=title, pos=pos, size=size)
        
        self.grain = Grain()
        self.switcher = FxSwitch(input=self.grain.sig(),fx='Reverb')
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour("#DDDDDD")

        self.onOffText = wx.StaticText(self.panel, id=-1, label="Audio",
                                       pos=(28,10))
        self.onOff = wx.ToggleButton(self.panel, id=-1, label="on / off", 
                                     pos=(10,28))
        self.onOff.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio)

        self.chooseButton = wx.Button(self.panel, id=-1, label="Load snd...", 
                                      pos=(10,65))
        self.chooseButton.Bind(wx.EVT_BUTTON, self.loadSnd)

        fxs = ['Reverb', 'Disto', 'Degrade', 'Delay', 'Harmonizer']
        self.popupText = wx.StaticText(self.panel, id=-1, 
                                       label="Choose FX", pos=(10,100))
        self.popup = wx.Choice(self.panel, id=-1, pos=(8,118), choices=fxs)
        self.popup.Bind(wx.EVT_CHOICE, self.changeFx)

        self.surface1 = Surface1(self.panel, pos=(150,28), size=(400,200), 
                               callback=self.changeParamsFx)
                               
        self.surface2 = Surface2(self.panel, pos=(150,230), size=(400,200), 
                               callback=self.changeParamsGrain)
                               
        self.grainDurationText = wx.StaticText(self.panel, id=-1,label="Grain Duration : 0.0010",pos=(150,440),size=wx.DefaultSize)
        self.grainDuration = wx.Slider(self.panel, id=-1,value=50,minValue=0,maxValue=1265,pos=(150,462),size=(400,-1))
        self.grainDuration.Bind(wx.EVT_SLIDER, self.grainDurCtrl)
        
        self.zRatioText = wx.StaticText(self.panel, id=-1,label="Z Ratio : 0.500",pos=(150,500),size=wx.DefaultSize)
        self.zRatio = wx.Slider(self.panel, id=-1,value=500,minValue=0,maxValue=1011,pos=(150,522),size=(400,-1))
        self.zRatio.Bind(wx.EVT_SLIDER, self.zRatioCtrl)

    def handleAudio(self, evt):
        if evt.GetInt() == 1:
            s.start()
        
        else:
            s.stop()    

    def loadSnd(self, evt):
        wildcard = "All files|*.*|" \
               "AIFF file|*.aif;*.aiff;*.aifc;*.AIF;*.AIFF;*.Aif;*.Aiff|" \
               "Wave file|*.wav;*.wave;*.WAV;*.WAVE;*.Wav;*.Wave"
        dlg = wx.FileDialog(self, message="Choose a new soundfile...", 
                            wildcard=wildcard, style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if path != "":
                self.grain.changeTable(path)
                self.open_path = os.path.split(path)
        dlg.Destroy()        

    def changeFx(self, evt):
        self.switcher.changeFx(evt.GetString()) 
        
    def zRatioCtrl(self, evt):
        z = evt.GetInt() * 0.001
        zb = 1./z
        self.zRatioText.SetLabel("Z Ratio : %.3f" % z)
        self.switcher.setRatio(z)
        

    def changeParamsFx(self, x, y):
        self.switcher.changeX(x)
        self.switcher.changeY(y)
        
    def changeParamsGrain(self, x, y):
        self.grain.changeX(x)
        self.grain.changeY(y)
        
    def grainDurCtrl(self, evt):
        x = evt.GetInt() * 0.00002
        self.grainDurationText.SetLabel("Grain Duration : %.4f" % x)
        self.grain.grainDur(x)

app = wx.PySimpleApp()

mainFrame = MyFrame()
mainFrame.Show()

app.MainLoop()
